/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * StatusLightsPanel.java
 *
 * Created on 07 Feb 2011, 2:30:49 PM
 */
package za.co.pas.spaceandtime.component;

import java.awt.Color;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.apache.log4j.Logger;
import za.co.pas.business.abstracts.AbstractDataModel;
import za.co.pas.business.message.MessageObj;
import za.co.pas.business.message.StatusMessage;
import za.co.pas.business.message.StatusMessageObject;
import za.co.pas.business.mvc.BusinessMVC;
import za.co.pas.business.abstracts.AbstractView;
import za.co.pas.business.constant.Constant;
import za.co.pas.business.model.CountryDataModel;
import za.co.pas.business.model.ext.CompanyDetailModel;
import za.co.pas.business.model.ext.UserDetailModel;

/**
 *
 * @author alabuschagne
 */
public class StatusLightsPanel extends JPanel implements AbstractView, PropertyChangeListener
{

    private static Logger logger = Logger.getLogger(StatusLightsPanel.class);
    private static final Queue<StatusMessageObject> queueCon = new LinkedList<StatusMessageObject>();
    private static final Queue<StatusMessageObject> queueRead = new LinkedList<StatusMessageObject>();
    private static final Queue<StatusMessageObject> queueWrite = new LinkedList<StatusMessageObject>();
    private static final int NUMBER_OF_TICKS_MSG = 10;
    private int noNewMessageCountW = NUMBER_OF_TICKS_MSG;
    private int noNewMessageCountR = NUMBER_OF_TICKS_MSG;
    private boolean stopDueToErrorMsg = false;
    private boolean busy = false;
    private Timer timer;
    private TimerTask timerTask = new TimerTask()
    {

        @Override
        public void run()
        {
            SwingUtilities.invokeLater(new Runnable()
            {

                @Override
                public void run()
                {
                    //busy turn
                    doSpin();
                    if (!queueCon.isEmpty())
                    {
                        if (!stopDueToErrorMsg)
                        {
                            StatusMessageObject smo = queueCon.poll();
                            updateCon(smo.getStatus());
                            stopDueToErrorMsg = smo.getStatus() == StatusMessageObject.SMO_ERROR;
                        }
                    }
                    if (queueWrite.isEmpty())
                    {
                        if (!stopDueToErrorMsg)
                        {
                            noNewMessageCountW--;
                            if (noNewMessageCountW == 0)
                            {
                                noNewMessageCountW = NUMBER_OF_TICKS_MSG;
                                updateWrite(StatusMessageObject.SMO_CLEAR);
                            }
                        }
                    }
                    else
                    {
                        noNewMessageCountW = NUMBER_OF_TICKS_MSG;
                        if (!stopDueToErrorMsg)
                        {
                            StatusMessageObject smo = queueWrite.poll();
                            updateWrite(smo.getStatus());
                            stopDueToErrorMsg = smo.getStatus() == StatusMessageObject.SMO_ERROR;
                        }
                    }
                    if (queueRead.isEmpty())
                    {
                        if (!stopDueToErrorMsg)
                        {
                            noNewMessageCountR--;
                            if (noNewMessageCountR == 0)
                            {
                                noNewMessageCountR = NUMBER_OF_TICKS_MSG;
                                updateRead(StatusMessageObject.SMO_CLEAR);
                            }
                        }
                    }
                    else
                    {
                        noNewMessageCountR = NUMBER_OF_TICKS_MSG;
                        if (!stopDueToErrorMsg)
                        {
                            StatusMessageObject smo = queueRead.poll();
                            updateRead(smo.getStatus());
                            stopDueToErrorMsg = smo.getStatus() == StatusMessageObject.SMO_ERROR;
                        }
                    }
                }
            });
        }
    };

    /** Creates new form StatusLightsPanel */
    public StatusLightsPanel()
    {
        initComponents();
        init();
//        this.busyLabel.setVisible(false);
    }

    private void init()
    {
        Constant.mvc.addPropertyChangeListener(this);
        if(Constant.mvc.isInit())
        {
            ((UserDetailModel) Constant.mvc.getModel(BusinessMVC.USER_DETAIL_MODEL)).addPropertyChangeListener(this);
        }
        timer = new Timer();
        timer.scheduleAtFixedRate(timerTask, 10, 200);
    }

    public void addPropChangeListener(AbstractDataModel adm)
    {
        adm.addPropertyChangeListener(this);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        dbReadLabel = new javax.swing.JLabel();
        dbWriteLabel = new javax.swing.JLabel();
        busyLabel = new javax.swing.JLabel();

        setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.LOWERED));
        setLayout(new java.awt.BorderLayout());

        dbReadLabel.setFont(new java.awt.Font("Lucida Console", 1, 11)); // NOI18N
        dbReadLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        dbReadLabel.setText("█");
        dbReadLabel.setToolTipText("Reading from database");
        dbReadLabel.setOpaque(true);
        add(dbReadLabel, java.awt.BorderLayout.LINE_START);

        dbWriteLabel.setFont(new java.awt.Font("Lucida Console", 1, 11)); // NOI18N
        dbWriteLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        dbWriteLabel.setText("█");
        dbWriteLabel.setToolTipText("Writing to database");
        dbWriteLabel.setOpaque(true);
        add(dbWriteLabel, java.awt.BorderLayout.CENTER);

        busyLabel.setFont(new java.awt.Font("Lucida Console", 1, 11));
        busyLabel.setForeground(new java.awt.Color(0, 255, 0));
        busyLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        busyLabel.setText("░");
        busyLabel.setToolTipText("Busy...");
        add(busyLabel, java.awt.BorderLayout.EAST);
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel busyLabel;
    private javax.swing.JLabel dbReadLabel;
    private javax.swing.JLabel dbWriteLabel;
    // End of variables declaration//GEN-END:variables

    @Override
    public void modelPropertyChange(PropertyChangeEvent evt)
    {
        if (evt.getPropertyName().compareTo(MessageObj.STATUS_MESSAGE) == 0)
        {
            if (evt.getNewValue() instanceof StatusMessageObject)
            {
                StatusMessageObject smo = (StatusMessageObject) evt.getNewValue();
                if ((smo.getType() == StatusMessageObject.SMO_TYPE_DB) && (smo.getMessage().compareTo(StatusMessage.ALLOK) == 0))
                {
                    ((UserDetailModel) Constant.mvc.getModel(BusinessMVC.USER_DETAIL_MODEL)).addPropertyChangeListener(this);
                    ((CountryDataModel) Constant.mvc.getModel(BusinessMVC.COUNTRY_DATA_MODEL)).addPropertyChangeListener(this);
                    ((CompanyDetailModel) Constant.mvc.getModel(BusinessMVC.COMPANY_DETAIL_MODEL)).addPropertyChangeListener(this);
                    
                }
                else if (smo.getType() == StatusMessageObject.SMO_TYPE_BUSY_START)
                {
                    busy(true);
                }
                else if (smo.getType() == StatusMessageObject.SMO_TYPE_BUSY_END)
                {
                    busy(false);
                }
                addMessage(smo);
            }
        }
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt)
    {
        if (evt.getPropertyName().compareTo(MessageObj.STATUS_MESSAGE) == 0)
        {
            if (evt.getNewValue() instanceof StatusMessageObject)
            {
                StatusMessageObject smo = (StatusMessageObject) evt.getNewValue();
                if ((smo.getType() == StatusMessageObject.SMO_TYPE_DB) && (smo.getMessage().compareTo(StatusMessage.ALLOK) == 0))
                {
                    ((UserDetailModel) Constant.mvc.getModel(BusinessMVC.USER_DETAIL_MODEL)).addPropertyChangeListener(this);
                    ((CountryDataModel) Constant.mvc.getModel(BusinessMVC.COUNTRY_DATA_MODEL)).addPropertyChangeListener(this);
                    ((CompanyDetailModel) Constant.mvc.getModel(BusinessMVC.COMPANY_DETAIL_MODEL)).addPropertyChangeListener(this);
                }
                else if (smo.getType() == StatusMessageObject.SMO_TYPE_BUSY_START)
                {
                    busy(true);
                }
                else if (smo.getType() == StatusMessageObject.SMO_TYPE_BUSY_END)
                {
                    busy(false);
                }
                addMessage(smo);
            }
        }
    }

    public void addMessage(StatusMessageObject smo)
    {
        if (smo.getType() == StatusMessageObject.SMO_TYPE_DB)
        {
            synchronized (queueCon)
            {
                queueCon.add(smo);
                logger.info("General db action");
            }
        }
        if (smo.getType() == StatusMessageObject.SMO_TYPE_READ)
        {
            synchronized (queueRead)
            {
                queueRead.add(smo);
                logger.info("Read from db");
            }
        }
        if (smo.getType() == StatusMessageObject.SMO_TYPE_WRITE)
        {
            synchronized (queueWrite)
            {
                queueWrite.add(smo);
                logger.info("Write to db");
            }
        }
        logger.info(smo.getMessage());
    }

    public void updateCon(int status)
    {
        final int st = status;
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                switch (st)
                {
                    case StatusMessageObject.SMO_ERROR:
                    {
                        busyLabel.setForeground(Color.RED);
                        break;
                    }
                    case StatusMessageObject.SMO_INFO:
                    {
                        busyLabel.setForeground(Color.GREEN);
                        break;
                    }
                    case StatusMessageObject.SMO_WARN:
                    {
                        busyLabel.setForeground(Color.YELLOW);
                        break;
                    }
                    case StatusMessageObject.SMO_CLEAR:
                    {
                        busyLabel.setForeground(Color.BLACK);
                        break;
                    }
                }
            }
        });
    }

    public void updateWrite(int status)
    {
        final int st = status;
        SwingUtilities.invokeLater(new Runnable()
        {

            @Override
            public void run()
            {
                switch (st)
                {
                    case StatusMessageObject.SMO_ERROR:
                    {
                        dbWriteLabel.setForeground(Color.RED);
                        break;
                    }
                    case StatusMessageObject.SMO_INFO:
                    {
                        dbWriteLabel.setForeground(Color.GREEN);
                        break;
                    }
                    case StatusMessageObject.SMO_WARN:
                    {
                        dbWriteLabel.setForeground(Color.YELLOW);
                        break;
                    }
                    case StatusMessageObject.SMO_CLEAR:
                    {
                        dbWriteLabel.setForeground(Color.BLACK);
                        break;
                    }
                }
            }
        });
    }

    public void updateRead(int status)
    {
        final int st = status;
        SwingUtilities.invokeLater(new Runnable()
        {

            @Override
            public void run()
            {
                switch (st)
                {
                    case StatusMessageObject.SMO_ERROR:
                    {
                        dbReadLabel.setForeground(Color.RED);
                        break;
                    }
                    case StatusMessageObject.SMO_INFO:
                    {
                        dbReadLabel.setForeground(Color.GREEN);
                        break;
                    }
                    case StatusMessageObject.SMO_WARN:
                    {
                        dbReadLabel.setForeground(Color.YELLOW);
                        break;
                    }
                    case StatusMessageObject.SMO_CLEAR:
                    {
                        dbReadLabel.setForeground(Color.BLACK);
                        break;
                    }
                }
            }
        });
    }

    private void doSpin()
    {
        if (busy)
        {
            SwingUtilities.invokeLater(new Runnable()
            {

                @Override
                public void run()
                {
                    String s = busyLabel.getText();
                    char c = s.charAt(0);
                    switch (c)
                    {
                        case '░':
                        {
                            busyLabel.setText("▒");
                            break;
                        }
                        case '▒':
                        {
                            busyLabel.setText("▓");
                            break;
                        }
                        case '▓':
                        {
                            busyLabel.setText("█");
                            break;
                        }
                        case '█':
                        {
                            busyLabel.setText("░");
                            break;
                        }
                        default:
                        {
                            busyLabel.setText("░");
                            break;
                        }
                    }
                }
            });
        }
    }

    private void busy(boolean onOff)
    {
        busy = onOff;
    }

    @Override
    public boolean isDirty()
    {
        return false;
    }

    @Override
    public String getExtraTitle()
    {
        return null;
    }
}
